#include <PreComp.h>

#pragma warning(disable:4201)

#include <MMSystem.h>

#ifdef PlaySound
#undef PlaySound
#endif

#include <SoundManager.h>
#include <DSound.h>
#include <DXUTSound.h>


struct SoundInitParams
{
    const char* szName;
    DWORD dwBufferCount;
    DWORD dwCaps;
};


const SoundInitParams c_rgSoundInitParams[] =
{
    { "Click", 1, 0 },
    { "Rollover", 1, 0 },
    { "EditboxType", 1, 0 },
    { "TorpFired", 4, DSBCAPS_CTRL3D  },
    { "PhaserFired", 4, DSBCAPS_CTRL3D  },
    { "Cloak", 3,   DSBCAPS_CTRL3D },
    { "Decloak", 3, DSBCAPS_CTRL3D },
    { "TorpHit", 4, DSBCAPS_CTRL3D },
    { "Tractor", 1, 0 },
};

CSoundManager::CSoundManager() : m_pDXSoundManager(NULL), m_pListener(NULL), m_pStreamingSound(NULL), m_hNeedsStreamingData(NULL)
{

}

void CSoundManager::LoadSounds()
{

    for(int i = 0; i < eSoundType_Count; i++)
    {
        char szBuffer[160];
        _snprintf_s(szBuffer, sizeof(szBuffer) - 1, _TRUNCATE, "Media\\Sounds\\%s.wav", c_rgSoundInitParams[i].szName);
        CDXSound* pSound = NULL;

        m_pDXSoundManager->Create( &pSound, szBuffer, c_rgSoundInitParams[i].dwCaps | DSBCAPS_CTRLVOLUME, GUID_NULL, c_rgSoundInitParams[i].dwBufferCount);
        m_rgpSoundList.push_back(pSound);
    }
}

void CSoundManager::ClearSounds()
{
    for_each(m_rgpSoundList.begin(), m_rgpSoundList.end(), DeleteChild());

    m_rgpSoundList.clear();
}

void CSoundManager::Initialize()
{
    m_pDXSoundManager = new CDXSoundManager();
    m_pDXSoundManager->Initialize(GetActiveWindow(), DSSCL_PRIORITY);

    m_pDXSoundManager->Get3DListenerInterface(&m_pListener);
    m_pListener->SetRolloffFactor(2.5f, DS3D_IMMEDIATE);

    LoadSounds();
}

void CSoundManager::PlaySound(ESoundType eSoundType, EPlaySoundFlags ePlaySoundFlags)
{
    DWORD dwFlags = 0;

    if(ePlaySoundFlags & ePlaySoundFlags_Loop)
    {
        dwFlags = DSBPLAY_LOOPING;
    }
    CDXSound* pSound = m_rgpSoundList[eSoundType];

    pSound->Play(0, dwFlags, -1000);
}

void CSoundManager::StopSound(ESoundType eSoundType)
{
    CDXSound* pSound = m_rgpSoundList[eSoundType];

    pSound->Stop();
}


void CSoundManager::PlaySoundStreaming(EStreamingSoundType, EPlaySoundFlags)
{
    m_hNeedsStreamingData = CreateEvent(NULL, FALSE, FALSE, NULL);
    m_pDXSoundManager->CreateStreaming(&m_pStreamingSound, "Media\\Sounds\\MusicDefault.wav", 
                                        DSBCAPS_LOCSOFTWARE | DSBCAPS_CTRLVOLUME, GUID_NULL, 2, 1024*64, m_hNeedsStreamingData);
    m_pStreamingSound->Play(0, DSBPLAY_LOOPING, -1000);
}

void CSoundManager::PlaySound3D(ESoundType eSoundType, const Ogre::Vector3& vectorLocation, EPlaySoundFlags ePlaySoundFlags)
{
    DWORD dwFlags = 0;

    if(ePlaySoundFlags & ePlaySoundFlags_Loop)
    {
        dwFlags = DSBPLAY_LOOPING;
    }
    CDXSound* pSound = m_rgpSoundList[eSoundType];

    DS3DBUFFER dsBuffer = { 0 };
    dsBuffer.dwSize = sizeof(DS3DBUFFER);

    dsBuffer.vPosition.x = vectorLocation.x;
    dsBuffer.vPosition.y = vectorLocation.y;
    dsBuffer.vPosition.z = vectorLocation.z;
    dsBuffer.vConeOrientation.y = 1.0f;
    dsBuffer.flMinDistance = 4000.0f;
    dsBuffer.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
    dsBuffer.dwMode = DS3DMODE_NORMAL;

    pSound->Play3D(&dsBuffer, dwFlags);
}

void CSoundManager::SetListenerPosition(const Ogre::Vector3& listenerPosition)
{
    if(m_pListener != NULL)
    {
        m_vectorListener = listenerPosition;
        m_pListener->SetPosition(listenerPosition.x, listenerPosition.y, listenerPosition.z, DS3D_IMMEDIATE);
    }
}

void CSoundManager::Update()
{
    if(m_pStreamingSound != NULL)
    {
        if(WaitForSingleObject(m_hNeedsStreamingData, 0) == WAIT_OBJECT_0)
        {
            m_pStreamingSound->HandleWaveStreamNotification(FALSE);
        }
    }
}

void CSoundManager::Cleanup()
{
    ClearSounds();

    m_pListener->Release();
    m_pListener = NULL;

    delete m_pDXSoundManager;
    m_pDXSoundManager = NULL;
}


